package event

import (
	"reflect"
	"gitee.com/wint/tge/log"
	"gitee.com/wint/tge/worker"
)

// 事件模块

// 事件监听器接口
type EventListener interface {
	OnEvent(string, interface{})
}

type ListenerFunc func(interface{})

func (fn ListenerFunc) OnEvent(evtName string, i interface{}) {
	fn(i)
}

type listener struct {
	Name 	string
	Ln 		EventListener
}

// 事件分发管理器
type EventDispatcher struct {
	_listeners	map[string][]EventListener
	_addListeners	[]*listener
	_removeListeners 	[]*listener
	_eventing 	bool
}

func NewEventDispatcher() *EventDispatcher {
	d := &EventDispatcher{}
	d._listeners = make(map[string][]EventListener)
	return d
}

func (d *EventDispatcher) On(evtName string, ln EventListener) {
	if d._eventing {
		d._addListeners = append(d._addListeners, &listener{evtName, ln})
	} else {
		d._on(evtName, ln)
	}
}

func (d *EventDispatcher) Off(evtName string, ln EventListener) {
	if d._eventing {
		d._removeListeners = append(d._removeListeners, &listener{evtName, ln})
	} else {
		d._off(evtName, ln)
	}
}

func (d *EventDispatcher) OffListener(ln EventListener) {
	if d._eventing {
		d._removeListeners = append(d._removeListeners, &listener{"", ln})
	} else {
		d._off("", ln)
	}
}

func (d *EventDispatcher) OffEvent(evtName string) {
	if d._eventing {
		d._removeListeners = append(d._removeListeners, &listener{evtName, nil})
	} else {
		d._off(evtName, nil)
	}
}

func (d *EventDispatcher) Emit(evtName string, arg interface{}) {
	// defer func() {
	// } ()
	d._eventing = true
	d._emit(evtName, arg)
	d._eventing = false
	if len(d._removeListeners) > 0 {
		for _, v := range d._removeListeners {
			d._off(v.Name, v.Ln)
		}
		d._removeListeners = d._removeListeners[:0]
	}
	if len(d._addListeners) > 0 {
		for _, v := range d._addListeners {
			d._on(v.Name, v.Ln)
		}
		d._addListeners = d._addListeners[:0]
	}
}

func (d *EventDispatcher) _emit(evtName string, arg interface{}) {
	defer func() {
		if err := recover(); err != nil {
  			log.Print("EventDispatcher Emit: ", evtName, arg, err)
  		}
	} ()
	if hs, ok := d._listeners[evtName]; ok {
		for i := 0; i < len(hs); i++ {
			v := hs[i]
			worker.RunWork(func() {
				v.OnEvent(evtName, arg)	
			})
		}
	}
}

func (d *EventDispatcher) _on(evtName string, ln EventListener) {
	if hs, ok := d._listeners[evtName]; ok {
		p1 := reflect.ValueOf(ln).Pointer()
		for _, v := range hs {
			if reflect.ValueOf(v).Pointer() == p1 {
				log.Print("EventDispatcher Error same listener", evtName, ln)
				return
			}
		}
		d._listeners[evtName] = append(hs, ln)
	} else {
		d._listeners[evtName] = []EventListener{ln}
	}
}

func (d *EventDispatcher) _off(evtName string, ln EventListener) {
	p1 := reflect.ValueOf(ln).Pointer()
	if "" == evtName {
		for key, hs := range d._listeners {
			for k, v := range hs {
				if reflect.ValueOf(v).Pointer() == p1 {
					d._listeners[key] = append(hs[:k], hs[k+1:]...)
					break
				}
			}
		}
	} else if hs, ok := d._listeners[evtName]; ok {
		if nil == ln {
			delete(d._listeners, evtName)
		} else {
			for k, v := range hs {
				if reflect.ValueOf(v).Pointer() == p1 {
					d._listeners[evtName] = append(hs[:k], hs[k+1:]...)
					break
				}
			}
		}
	}
}

var dispatcher = NewEventDispatcher()

func On(evtName string, ln EventListener) {
	dispatcher.On(evtName, ln)
}

func Off(evtName string, ln EventListener) {
	dispatcher.Off(evtName, ln)
}

func OffListener(ln EventListener) {
	dispatcher.OffListener(ln)
}

func OffEvent(evtName string) {
	dispatcher.OffEvent(evtName)
}

func Emit(evtName string, arg interface{}) {
	dispatcher.Emit(evtName, arg)
}